/** 
 * Links:compute links between to points
 * input file:
 *   simMatrixPath: keyword,weight,[(keyword_i,sim_i)(keyword_j,sim_j)...] \n
 * output file:
 *   linksMatrixPath: keyword,weight,[(keyword_i,neighbors_num_i)(keyword_j,neighbors_num_j)...]\n
 */
package cluster.links;
import java.io.*;
import java.util.ArrayList;
import common.Word;
import common.Config;
import preprocess.similarity.SimItem;
import preprocess.similarity.SimRecord;

public class Links{
	private ArrayList<LinkRecord> linksMatrix = new ArrayList<LinkRecord>();

    /**
     * 将[(keyword,sim),(..,..)...]型字符串转换成ArrayList
     */
	private ArrayList<SimItem> strToList( String str ){
		ArrayList<SimItem> slist = new ArrayList<SimItem>();
		try{
			str = str.trim().substring( 2,str.length()-2 );
			String[] pair = str.split("\\), \\(");
			for( int i=0;i<pair.length;i++){
				String[] items = pair[i].split(",");
				slist.add( new SimItem( items[0],Float.parseFloat(items[1]) ));
			}

		}catch( IndexOutOfBoundsException e ){
			System.out.println( "data formart wrong,cannot transform to ArrayList:"+str);
			System.exit( 1 );
		}
		return slist;
	}

	/**
	 *  read data from similarity files
	 * @return keywords similarity matrix
	 * @throws IOException
	 */
	private ArrayList<SimRecord> readData() throws IOException{
		String path = Config.simMatrixPath;
		ArrayList< SimRecord > simMatrix = new ArrayList< SimRecord >();

		try{
			FileReader fr = new FileReader( path );
			BufferedReader br = new BufferedReader( fr );

			String line = br.readLine();
			int lineno = 0;
			while( line != null ){
				String[] items = line.trim().split(",",3);
				try{
					SimRecord sr = new SimRecord( new Word(items[0],Float.parseFloat( items[1] )) );
					sr.colist = strToList( items[ 2 ] );
					simMatrix.add( sr );
				}catch( NumberFormatException e ){
					System.err.println( "Wrong record:"+line +""+e.toString());
					System.exit( 1 );
				}
				lineno++;
				line = br.readLine();
			}
			br.close();
			fr.close();
		}catch( FileNotFoundException e ){
			System.err.println( path + " not found!" );
			System.exit(1);
		}
		return simMatrix;
	}
    /**
     * request link record by keyword,if not exsit,create it with word and 
     * weight info
     */
    private LinkRecord requestLinkRecord( String keyword ){
       // find record whose keyword equal word
       for( int i=0;i<linksMatrix.size();i++ ){
           if( linksMatrix.get(i).getKeyword().equals( keyword ) ){
                return linksMatrix.get(i);
            		}
        	}
       System.exit( 1 );
       return null;
    	}
    /**
     * add keyword to li,if already exsit,increasing the recounter
     */
    private void addSingleLink( LinkRecord lr,String keyword ){
        // find whether a LinkItem contain this keyword
	    LinkItem link = lr.findLink( keyword );
	    if( link != null ){
		    link.increaseNum();
		}
	    else{
			lr.newLink( keyword );
	    }
    }
    /**
     * add link relationship both for lr and another
     */
    private void addLinks( LinkRecord lr,LinkRecord another ){
        addSingleLink( lr,another.getKeyword() );
        addSingleLink( another,lr.getKeyword() );
    }

    /**
     * give a keyword's correlate keywords list,compute links between
     * keywords pairs in list
     */
    private void trackLinks( ArrayList<Word> words ){
        for( int i=0;i<words.size();i++ ){
            LinkRecord lr = requestLinkRecord( words.get(i).getKeyword() );
            for( int j=i+1;j<words.size();j++ ){
                LinkRecord another = requestLinkRecord( words.get(j).getKeyword() );
                addLinks( lr,another );
            		}
        		
        }
    	}

	private void computeLinks( ArrayList<SimRecord> simMatrix ){
		//fill in linkMatrix with keyword info
		for( int i=0;i<simMatrix.size();i++ ){
			LinkRecord lr = new LinkRecord( simMatrix.get(i).getKeyword() );
			linksMatrix.add( lr );
		}
		
		// fill in linkMatrix with link info of keywords
		for( int i=0;i<simMatrix.size();i++ ){
            SimRecord sr = simMatrix.get( i );           
            ArrayList<Word> words = sr.extractWords();
            trackLinks( words );
            //debug
            System.out.println( "compute links for record:"+i );
		}
	}
	/**
	 * remove the links whose num  < Config.minLinks
	 */
	private void pruneLinks(){
		for( int i=0;i<linksMatrix.size(); ){
			linksMatrix.get(i).pruneLinks();
			// if no link remain,remove it
			if( linksMatrix.get(i).numLinks() == 0 ){
				linksMatrix.remove(i);
			}
			else{
				i++;
			}
		}
	}
	
    private void writeResult() throws IOException{
        FileWriter fw = new FileWriter( Config.linksMatrixPath );
        for( int i=0;i<linksMatrix.size();i++ ){
	        if( linksMatrix.get(i).linkList.size()>0 ){
		        fw.write( linksMatrix.get(i).toString()+"\n" );
	        }
        }
        fw.close();
    }

	public void run() throws IOException{
		ArrayList<SimRecord> simMatrix = readData();
        System.out.println("readData finished!");
        computeLinks( simMatrix );
		System.out.println("computeLinks finished!");
		pruneLinks();
		System.out.println("pruneLinks finished!");
        writeResult();
		System.out.println("writeResult finished:"+Config.linksMatrixPath );
    }

    public static void main( String[] args ) throws IOException{
       Links mylinks = new Links();
		mylinks.run();		
		System.out.println("3.Compute links between keywords Completed!");
    }
}